#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <opencv2/opencv.hpp>
#include "HTEffectInterfaceWin.h"
#include <glfw3.h>
#include <glad/glad.h>
#include <tchar.h>
#include "license.h"

#define LOG_TAG "HTEffect"
#define LOG_I(...) { fprintf(stdout,"%s%s",LOG_TAG," : "); fprintf(stdout,__VA_ARGS__); fprintf(stdout,"\n"); }
#define LOG_E(...) { fprintf(stderr,"%s%s",LOG_TAG," : "); fprintf(stderr,__VA_ARGS__); fprintf(stderr,"\n"); }

const int kFrameInterval = 1;

/**
* CurrentMillisecondTime
* get current millisecond time, to calculate execution time
*
* @return current millisecond time, double format
*/
double CurrentMillisecondTime() {
	return (double)GetTickCount64() * 0.001f;
}

void DoFrameMirror(cv::Mat& image, bool is_mirror) {
	if (is_mirror) {
		cv::flip(image, image, 1);
	}
}

void DrawFrameInfo(cv::Mat& image) {
	//cv::putText(image, "frame rate: " + std::to_string((int)(1000 / kFrameInterval)), cv::Point(30, 30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 0, 0));

	cv::putText(image, "frame size: " + std::to_string(image.cols) + " " + std::to_string(image.rows), cv::Point(30, 60), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 0, 0));
}

PIXELFORMATDESCRIPTOR pfd = {
	sizeof(PIXELFORMATDESCRIPTOR),
	1u,
	PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW,
	PFD_TYPE_RGBA,
	32u,
	0u, 0u, 0u, 0u, 0u, 0u,
	8u,
	0u,
	0u,
	0u, 0u, 0u, 0u,
	24u,
	8u,
	0u,
	PFD_MAIN_PLANE,
	0u,
	0u, 0u };

void InitOpenGL()
{

	HWND hw = CreateWindowExA(
		0, "EDIT", "", ES_READONLY,
		0, 0, 1, 1,
		NULL, NULL,
		GetModuleHandleA(NULL), NULL);
	HDC hgldc = GetDC(hw);
	int spf = ChoosePixelFormat(hgldc, &pfd);
	int ret = SetPixelFormat(hgldc, spf, &pfd);
	HGLRC hglrc = wglCreateContext(hgldc);
	wglMakeCurrent(hgldc, hglrc);
	printf("hw=%08x hgldc=%08x spf=%d ret=%d hglrc=%08x\n",
		hw, hgldc, spf, ret, hglrc);

	//Init GL and Window
}
//GLFWwindow* window;

void main() {
	//  HTEffect SDK auth
	int initStatus = HTE::authorizeSDK(hte_license_str.c_str(), ".\\..\\HTEffectBundle");
	LOG_I("HTEffect init status: %d", initStatus);

	// print opencv version string
	LOG_I("opencv version is : %s", cv::getVersionString().c_str());

	// init OpenGL

	cv::VideoCapture capture(0);
	//capture.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
	//capture.set(cv::CAP_PROP_FRAME_HEIGHT, 720);
	bool isInitHTEffect = false;
	while (capture.isOpened()) {
		//glClear(GL_COLOR_BUFFER_BIT);
		//glClearColor(0.0f, 0.0f, 0.1f, 0.0f);

		cv::Mat frame;
		capture >> frame;

		if (frame.empty()) {
			break;
		}

		// process start
		double st = CurrentMillisecondTime();
		cv::cvtColor(frame, frame, cv::COLOR_BGR2RGBA);
		// init HTEffect renderer
		if (!isInitHTEffect) {
			isInitHTEffect = HTE::initBufferRenderer(3, frame.cols, frame.rows, 0, false, 5);
		}
		// HTEffect functions
		HTE::setARItem(0, "ht_sticker_effect_rabbit_bowknot");
		HTE::setReshape(HTE::HTE_W_HTReshapeEyeEnlarging, 80);
		HTE::setReshape(HTE::HTE_W_ReshapeCheekThinning, 80);
		HTE::setFilter(HTE::HTE_W_FilterBeauty, "ziran3");
		// HTEffect process 
		HTE::processBuffer(frame.data);

		cv::cvtColor(frame, frame, cv::COLOR_RGBA2BGR);
		double et = CurrentMillisecondTime();
		LOG_I("process cost time: %lf ms", et - st);
		// process end

		DoFrameMirror(frame, true);
		DrawFrameInfo(frame);

		const char* name = "Opencv Camera";
		cv::namedWindow(name, 1);
		cv::imshow(name, frame);

		cv::waitKey(kFrameInterval);
	}
}